3-7 騕硎c}CBz

MATLAB 也提供比較複雜的資料結構,例如結構陣列、異質陣列等。我們也可以撰寫C程式碼,來和MATLAB內部的結構陣列進行資料的交換和計算。 在下面這個範例 matlabStruct2c.c,我們將 MATLAB 的結構陣列,送到 C 程式碼內部的結構陣列,程式碼如下:

原始檔(03-應用程式介面/matlabStruct2c.c):(灰色區域按兩下即可拷貝)
// 此範例說明如何由 MATLAB 的結構陣列轉成 C 的結構陣列
// Roger Jang, 20050402

#include "mex.h"
#include <string.h>

#define	IN	prhs[0]		// 定義輸出變數

typedef struct {
	char *name;
	double phone;
} PHONEBOOK;
PHONEBOOK *friend;	// C 的結構陣列

void
mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[]) {
	int i, elementNum, strLen, status;

	// 檢查輸入和輸出參數的個數
	if (nrhs<1) mexErrMsgTxt("One input argument required.");
	if (nlhs>0) mexErrMsgTxt("No output argument required.");

	elementNum = mxGetNumberOfElements(IN);		// 元素個數
	friend = (PHONEBOOK *)malloc(elementNum*sizeof(PHONEBOOK));	// 產生 C 的結構陣列
    
	// 填入 C 結構陣列的欄位值
	for (i=0; i<elementNum; i++) {
		// 填入 phone 欄位
		mxArray *fieldValue;
		fieldValue = mxGetField(IN, i, "phone");
		friend[i].phone = *mxGetPr(fieldValue);
		// 填入 name 欄位
		fieldValue = mxGetField(IN, i, "name");
		strLen = (2*mxGetM(fieldValue)*mxGetN(fieldValue))+1;	// 乘上2, 以對付 2-byte 中文字
		friend[i].name = (char *)malloc(strLen*sizeof(char));
		status = mxGetString(fieldValue, friend[i].name, strLen);
		if(status != 0) 
			mexWarnMsgTxt("Not enough space. String is truncated.");
	}

	// 列印 C 結構陣列
	for (i=0; i<elementNum; i++) {
		printf("friend[%d].name = %s\n", i, friend[i].name);
		printf("friend[%d].phone = %f\n", i, friend[i].phone);
	}

	// Free memory
	for (i=0; i<elementNum; i++)
		free(friend[i].name);
	free(friend);
}

可編譯及測試如下:

Example 1: 03-應用程式介面/matlabStruct2c01.mmex matlabStruct2c.c x(1).name = '林政源'; x(1).phone = 2796; x(2).name = '陳江村'; x(2).phone = 3425; x(3).name = '張永森'; x(3).phone = 3213; matlabStruct2c(x)friend[0].name = 林政源 friend[0].phone = 2796.000000 friend[1].name = 陳江村 friend[1].phone = 3425.000000 friend[2].name = 張永森 friend[2].phone = 3213.000000

其中由 MATLAB 印出來的訊息,事實上已經是 C 程式碼的結構陣列的欄位值。

下面這個範例 cStruct2matlab.c,則是反其道而行,也就是將 C 的結構陣列,送到 MATLAB 工作空間的結構陣列,如下:

原始檔(03-應用程式介面/cStruct2matlab.c):(灰色區域按兩下即可拷貝)
// 此範例說明如何由 C 的結構陣列轉成 MATLAB 的結構陣列
// Roger Jang, 20050402

#include "mex.h"
#include <string.h>

#define	OUT	plhs[0]		// 定義輸出變數

struct phonebook {
	const char *name;
	double phone;
};
// C 的結構陣列
struct phonebook friends[] = {{"李宏儒", 3486},{"林政源",3712}, {"陳江村", 2248}};
// 用於 MATLAB 結構陣列的欄位名稱
const char *fieldNames[] = {"name", "phone"};

void
mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[]) {
	int structNum = sizeof(friends)/sizeof(struct phonebook);	// 結構陣列的長度
	int fieldNum = sizeof(fieldNames)/sizeof(*fieldNames);		// 欄位的個數
	int dims[2] = {1, structNum};					// 結構陣列的維度
	int i, nameFieldIndex, phoneFieldIndex;

	// 檢查輸入和輸出參數的個數
	if (nrhs>0) mexErrMsgTxt("No input argument required.");
	if (nlhs>1) mexErrMsgTxt("Too many output arguments.");
    
	// 產生輸出結構陣列
	OUT = mxCreateStructArray(2, dims, fieldNum, fieldNames);

	// 取得欄位名稱對應的索引值,以便使用 mxSetFieldByNumber() 對欄位值進行設定
	nameFieldIndex = mxGetFieldNumber(OUT, "name");
	phoneFieldIndex = mxGetFieldNumber(OUT, "phone");

	// 填入 MATLAB 結構陣列的欄位值
	for (i=0; i<structNum; i++) {
		mxArray *fieldValue;
		// 填入欄位名稱 name 的值(有兩種方法)
	//	mxSetField(OUT, i, "name", mxCreateString(friends[i].name));			// 方法一:效率較低
		mxSetFieldByNumber(OUT, i, nameFieldIndex, mxCreateString(friends[i].name));	// 方法二:效率較高
		// 填入欄位名稱 phone 的值(有兩種方法)
		fieldValue = mxCreateDoubleMatrix(1, 1, mxREAL);
		*mxGetPr(fieldValue) = friends[i].phone;
	//	mxSetField(OUT, i, "phone", fieldValue);					// 方法一:效率較低
		mxSetFieldByNumber(OUT, i, phoneFieldIndex, fieldValue);	// 方法二:效率較高
	}
}

可編譯及測試如下:

Example 2: 03-應用程式介面/cStruct2matlab01.mmex cStruct2matlab.c x = cStruct2matlabx = 1x3 struct array with fields: name phone

其中 MATLAB 在工作空間的結構陣列 x 即是由 C 的結構陣列轉換出來的結果。
MATLAB程式設計:進階篇